package com.msite.config;

import org.activiti.engine.IdentityService;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.identity.Group;
import org.activiti.engine.identity.User;
import org.activiti.spring.ProcessEngineFactoryBean;
import org.activiti.spring.SpringProcessEngineConfiguration;
import org.apache.commons.dbcp.BasicDataSource;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import javax.sql.DataSource;

/**
 * Created by tpeng on 2016/4/14.
 */
@Configuration
@EnableConfigurationProperties
@ConfigurationProperties(prefix = "activi")
@ConditionalOnExpression("${activi.enable:false}")
@Order(2)
public class ActivityConfig {

    @Value("${dbEnable:false}")
    boolean dbEnable;

    String username;
    String password;
    String url;
    String driverClassName;

    @Value("${fontName:'宋体'}")
    String fontName;
    @Value("${jobExecutorActivate:false}")
    boolean jobExecutorActivate;

    @Value("${initialSize:0}")
    int initialSize;
    @Value("${maxActive:5}")
    int maxActive;
    @Value("${maxIdle:8}")
    int maxIdle;
    @Value("${minIdle:0}")
    int minIdle;
    @Value("${maxWait:1000}")
    int maxWait;

    @Bean(name = "activitDataSource", destroyMethod = "close")
    public DataSource activitDataSource(){
        if(!dbEnable){
            return null;
        }
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setUsername(this.username);
        dataSource.setPassword(this.password);
        dataSource.setUrl(this.url);
        dataSource.setDriverClassName(this.driverClassName);
        dataSource.setInitialSize(this.initialSize);
        dataSource.setMaxActive(this.maxActive);
        dataSource.setMaxIdle(this.maxIdle);
        dataSource.setMinIdle(this.minIdle);
        dataSource.setMaxWait(this.maxWait);
        //dataSource.setValidationQuery(this.validationQuery);
        dataSource.setRemoveAbandoned(true);
        dataSource.setRemoveAbandonedTimeout(300);
        dataSource.setLogAbandoned(true);
        return dataSource;
    }

    /*
      Activiti 用户手册
      http://www.mossle.com/docs/activiti/index.html
     */
    @Bean(name = "processEngineConfiguration")
    public SpringProcessEngineConfiguration springProcessEngineConfiguration(
            @Qualifier("dataSource") DataSource dataSource,
            @Qualifier("transactionManager") DataSourceTransactionManager transactionManager
    ) throws Exception{
        SpringProcessEngineConfiguration configuration = new SpringProcessEngineConfiguration();
        configuration.setActivityFontName(fontName);
        configuration.setLabelFontName(fontName);
        configuration.setDataSource((this.dbEnable ? activitDataSource() : dataSource));
        configuration.setDatabaseSchemaUpdate(SpringProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
        //configuration.setDatabaseType("h2");
        configuration.setJdbcUsername(this.username);
        configuration.setJdbcPassword(this.password);
        configuration.setJobExecutorActivate(jobExecutorActivate);
        configuration.setAsyncExecutorEnabled(true);
        configuration.setAsyncExecutorActivate(false);
        configuration.setTransactionManager(!dbEnable ? transactionManager : activitTransactionManager());

        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        Resource[] resources = resolver.getResources("classpath*:processes/*.bpmn20.xml");
        configuration.setDeploymentResources(resources);

        /*configuration.setMailServerHost(mailServerHost);
        configuration.setMailServerPort(mailServerPort);*/
        return configuration;
    }

    @Bean
    public ProcessEngineFactoryBean processEngineFactoryBean
            (SpringProcessEngineConfiguration processEngineConfiguration){
        ProcessEngineFactoryBean processEngineFactoryBean = new ProcessEngineFactoryBean();
        processEngineFactoryBean.setProcessEngineConfiguration(processEngineConfiguration);
        return processEngineFactoryBean;
    }

    @Bean(name = "activitTransactionManager")
    public DataSourceTransactionManager activitTransactionManager(){
        DataSource ds = activitDataSource();
        return ds == null ? null : new DataSourceTransactionManager(ds);
    }



    /*@Bean
    CommandLineRunner init( final RepositoryService repositoryService,
                            final RuntimeService runtimeService,
                            final TaskService taskService) {

        return new CommandLineRunner() {

            public void run(String... strings) throws Exception {
                Map<String, Object> variables = new HashMap<String, Object>();
                variables.put("applicantName", "John Doe");
                variables.put("email", "john.doe@activiti.com");
                variables.put("phoneNumber", "123456789");
                runtimeService.startProcessInstanceByKey("hireProcess", variables);
            }
        };
    }*/

    @Bean
    InitializingBean usersAndGroupsInitializer(final ProcessEngine processEngine,final IdentityService identityService) {

        return new InitializingBean() {
            public void afterPropertiesSet() throws Exception {
                processEngine.getProcessEngineConfiguration().setActivityFontName(fontName);
                processEngine.getProcessEngineConfiguration().setLabelFontName(fontName);

                if(identityService.createGroupQuery().groupId("user").count() == 0) {
                    Group group = identityService.newGroup("user");
                    group.setName("users");
                    group.setType("security-role");
                    identityService.saveGroup(group);
                }

                if(identityService.createUserQuery().userId("admin").count() == 0) {
                    User admin = identityService.newUser("admin");
                    admin.setPassword("admin");
                    identityService.saveUser(admin);
                }

            }
        };
    }


    public boolean isDbEnable() {
        return dbEnable;
    }

    public void setDbEnable(boolean dbEnable) {
        this.dbEnable = dbEnable;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getDriverClassName() {
        return driverClassName;
    }

    public void setDriverClassName(String driverClassName) {
        this.driverClassName = driverClassName;
    }

    public String getFontName() {
        return fontName;
    }

    public void setFontName(String fontName) {
        this.fontName = fontName;
    }

    public boolean isJobExecutorActivate() {
        return jobExecutorActivate;
    }

    public void setJobExecutorActivate(boolean jobExecutorActivate) {
        this.jobExecutorActivate = jobExecutorActivate;
    }

    public int getInitialSize() {
        return initialSize;
    }

    public void setInitialSize(int initialSize) {
        this.initialSize = initialSize;
    }

    public int getMaxActive() {
        return maxActive;
    }

    public void setMaxActive(int maxActive) {
        this.maxActive = maxActive;
    }

    public int getMaxIdle() {
        return maxIdle;
    }

    public void setMaxIdle(int maxIdle) {
        this.maxIdle = maxIdle;
    }

    public int getMinIdle() {
        return minIdle;
    }

    public void setMinIdle(int minIdle) {
        this.minIdle = minIdle;
    }

    public int getMaxWait() {
        return maxWait;
    }

    public void setMaxWait(int maxWait) {
        this.maxWait = maxWait;
    }
}
